package ee.ut.maxorato_macobo.oop.mud.game;

import java.lang.reflect.Method;
import java.util.ArrayList;

import ee.ut.maxorato_macobo.oop.mud.items.ItemBase;

public class GameSpellSystem {
	private static ArrayList<Class<? extends GameSpell>> spellMap = new ArrayList<Class<? extends GameSpell>>();
	
	public static class GameSpell {
		protected String params;
		protected PlayerCharacter player;
		
		public GameSpell() {
			
		}
		
		public void init(PlayerCharacter newPlayer, String newParams) {
			player = newPlayer;
			params = newParams;
		}
		
		public boolean execute() {
			return true;
		}
		
		public static String getSpellName() {
			return "none";
		}
		
		public int getManaCost() {
			return 0;
		}
	}
	
	public static void registerSpell(Class<? extends GameSpell> commandClass) {
		spellMap.add(commandClass);
	}
	
	public static void loadSpells() {
		registerSpell(SpellBlast.class);
		registerSpell(SpellDuplicate.class);
	}
	
	public static String getSpellName(Class<? extends GameSpell> spellClass) {
		Method cmdNameFunc;
		try {
			cmdNameFunc = spellClass.getDeclaredMethod("getSpellName", (Class[])null);
			return (String)cmdNameFunc.invoke(null, (Object[])null);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public static Class<? extends GameSpell> findSpellByPrefix(String findName) {
		for(Class<? extends GameSpell> spell : spellMap) {
			String spellName = getSpellName(spell);
			
			if(spellName != null && spellName.length() >= findName.length() && spellName.substring(0, findName.length()).equals(findName)) {
				return spell;
			}
		}
		
		return null;
	}
	
	public static void processAsSpell(PlayerCharacter player, String text) {
		String[] splitted = text.trim().split(" ", 2);
		
		String spellName = splitted[0].toLowerCase();
		String params = (splitted.length > 1) ? splitted[1] : "";
		
		try {
			if(spellName.length() < 1) throw new Exception();
			
			GameSpell spell = (GameSpell)findSpellByPrefix(spellName).newInstance();
			spell.init(player, params);
			
			if(spell.getManaCost() > player.getMana()) {
				player.sendTickMessage("You don't have enough mana to cast this spell.");
			}
			else {
				if(spell.execute()) {
					player.setMana(player.getMana() - spell.getManaCost());
				}
			}
		} catch (Exception e) {
			player.sendTickMessage("No such spell.");
		}
	}
	
	public static class SpellBlast extends GameSpell {
		public SpellBlast(){}
		public static String getSpellName() { return "blast"; }
		public int getManaCost() { return 30; }
		
		public boolean execute() {
			GameCharacter target = GameUtils.getTargetCharFromArgument(player.getRoom(), params);
			
			if(target == null) {
				target = player.getFightTarget();
			}
			
			if(target != null) {
				int finalHit = (int)((double)(player.randGen.nextInt(40) + 30) * Math.max(0.2, 1.0 - target.getDefenseAgainstMagic() / 100.0));
				
				player.showAttackMessage(target, "\033[1;37mblast", finalHit);
				target.applyHitDamageFrom(player, finalHit);
				
				target.gotAttackedBy(player);
				player.setDelayTicks(10);
			}
			else {
				player.sendTickMessage("No such character in this room.");
				return false;
			}
			
			return true;
		}
	}
	
	public static class SpellDuplicate extends GameSpell {
		public SpellDuplicate(){}
		public static String getSpellName() { return "duplicate"; }
		public int getManaCost() { return 80; }
		
		public boolean execute() {
			ItemBase item = GameUtils.getSubItemFromArgument(player, 'i', params);
			
			if(item != null) {
				item.clone().hashCode();
				
				player.sendTickMessage("You duplicated '" + item.getName() + "' in your inventory.");
			}
			else {
				player.sendTickMessage("No such item in your inventory.");
				return false;
			}
			
			return true;
		}
	}	
}
